import Module from "./Module"
import SettingsData from "../data/SettingsData"
import MattertagsData from "../data/MattertagsData"
import PinsModule from "./PinsModule"
import MattertagsViewData from "../data/MattertagsViewData"
import TextureLoader from "../loader/TextureLoader"

import pinTypeEnum from "../enum/pinType.enum"
import keyConst from "../constant/key.const"
import EngineContext from "../EngineContext"
import Mattertag from "../object/Mattertag"

export default class MattertagMeshModule extends Module {
  visibilityDirty: boolean
  unanchoredTagOpacity: number
  anchoredTagOpacity: number
  addNewTagMesh: any
  settings: SettingsData
  pinRenderer: PinsModule["pinRenderer"]
  removeTagMesh: any
  updateTagMesh: any
  initializeTagVisibility: () => void
  mattertagData: MattertagsData
  updateTagVisibilty: () => void
  selectedTagChanged: () => void
  mattertagViewData: MattertagsViewData
  anchorTagId: string
  constructor() {
    super(...arguments)
    this.name = "mattertag-mesh"
    this.visibilityDirty = !0
    this.unanchoredTagOpacity = 1
    this.anchoredTagOpacity = 1
    this.addNewTagMesh = (e: Mattertag, t) => {
      this.settings.tryGetProperty(keyConst.rule.features.tag, !1) ||
        this.pinRenderer.updatePin(
          e.sid,
          pinTypeEnum.MATTERTAG,
          Object.assign(Object.assign({}, e), {
            stemNormal: e.stemVector,
            stemLength: e.stemHeight,
            stemEnabled: e.stemVisible,
            color: `#${e.color.getHexString()}`
          }),
          this.backgroundTexture,
          this.maskTexture
        )
    }
    this.removeTagMesh = (e, t) => {
      this.pinRenderer.removePin(e.sid)
    }
    this.updateTagMesh = (e: Mattertag, t) => {
      this.addNewTagMesh(e, e.sid)
    }
    this.initializeTagVisibility = () => {
      //初始化显示
      if (this.settings.tryGetProperty(keyConst.rule.features.tag, !1)) return
      const e = this.settings.tryGetProperty(keyConst.rule.features.mattertags, !0)
      this.pinRenderer.setPinOpacityByType(pinTypeEnum.MATTERTAG, e ? 1 : 0),
        e &&
          this.mattertagData.iterate(e => {
            this.pinRenderer.setPinVisible(e.sid, e.enabled)
          })
    }
    this.updateTagVisibilty = () => {
      if (this.settings.tryGetProperty(keyConst.rule.features.tag, !1)) return
      this.settings.tryGetProperty(keyConst.rule.features.mattertags, !1)
        ? this.fadePinsToState()
        : this.pinRenderer.fadePinOpacityByType(pinTypeEnum.MATTERTAG, 0)
    }
    this.selectedTagChanged = () => {
      if (!this.settings.tryGetProperty(keyConst.rule.features.tag, !1)) {
        if (this.mattertagViewData.selectedTag && !this.mattertagViewData.navigating) {
          const e = this.mattertagData.getTag(this.mattertagViewData.selectedTag)
          this.pinRenderer.showSelectedMesh(pinTypeEnum.MATTERTAG, e.sid)
        }
        this.mattertagViewData.selectedTag || this.pinRenderer.hideSelectedMesh()
      }
    }
  }
  backgroundTexture: THREE.Texture
  maskTexture: THREE.Texture
  async init(e, t: EngineContext) {
    const [mattertagData, pin, settings, mattertagViewData] = await Promise.all([
      t.market.waitForData(MattertagsData),
      t.getModule(PinsModule),
      t.market.waitForData(SettingsData),
      t.market.waitForData(MattertagsViewData)
    ])
    this.settings = settings
    this.mattertagData = mattertagData
    this.mattertagViewData = mattertagViewData
    this.pinRenderer = pin.pinRenderer
    const m = () => {
      this.visibilityDirty = true
    }
    this.bindings.push(
      this.mattertagData.collection.onElementChanged({
        onAdded: this.addNewTagMesh,
        onRemoved: this.removeTagMesh,
        onUpdated: this.updateTagMesh
      }),
      this.mattertagViewData.onToolStateChanged(m),
      this.settings.onPropertyChanged(keyConst.rule.features.mattertags, m),
      this.mattertagData.onChanged(m),
      this.mattertagViewData.onSelectedTagChanged(this.selectedTagChanged),
      this.mattertagViewData.onNavigatingTagChanged(this.selectedTagChanged)
    )
    this.backgroundTexture = TextureLoader("./images/tagbg.png")
    this.maskTexture = TextureLoader("./images/tagmask.png")
    this.mattertagData.iterate(e => {
      this.addNewTagMesh(e, e.sid)
    })
    this.initializeTagVisibility()
  }
  dispose(e) {
    this.pinRenderer.removePinsByType(pinTypeEnum.MATTERTAG)
    this.backgroundTexture.dispose()
    this.maskTexture.dispose()
    super.dispose(e)
  }
  onUpdate(e) {
    this.visibilityDirty && ((this.visibilityDirty = !1), this.updateTagVisibilty())
  }
  showAnchorMesh(e) {
    this.pinRenderer.showAnchorMesh(
      pinTypeEnum.MATTERTAG,
      e.sid,
      Object.assign(Object.assign({}, e), {
        stemNormal: e.stemVector,
        stemLength: e.stemHeight
      })
    )
    this.unanchoredTagOpacity = 0.5
    this.anchoredTagOpacity = 1
    this.anchorTagId = e.sid
    this.fadePinsToState()
  }
  hideAnchorMesh() {
    this.unanchoredTagOpacity = 1
    this.anchoredTagOpacity = 1
    this.anchorTagId = undefined
    this.pinRenderer.hideAnchorMesh()
    this.fadePinsToState()
  }
  resetPinOpacity() {
    this.fadePinsToState()
  }
  changeDiscOpacity(e, t) {
    this.pinRenderer.setPinOpacity(e, t)
  }
  setTagVisibility(e) {
    this.pinRenderer.setPinTypeVisible(pinTypeEnum.MATTERTAG, e)
  }
  setTagVisible(e, t) {
    this.pinRenderer.setPinVisible(e, t)
  }
  setOverrideMaterial(e, t, i) {
    this.pinRenderer.setPinRenderOverrides(e, t, i)
  }
  fadePinsToState() {
    const { selectedTag: e } = this.mattertagViewData
    this.mattertagData.iterate(t => {
      const i = t.enabled || e === t.sid
      this.pinRenderer.setPinVisible(t.sid, i)
      const n = t.sid === this.anchorTagId ? this.anchoredTagOpacity : this.unanchoredTagOpacity
      this.pinRenderer.fadePinOpacity(t.sid, i ? n : 0)
    })
  }
}
